﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using ControleRepresentante.UnitTests.Mocks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebSite.Controllers;
using WebSite.ViewModels.DetailsViewModels;
using WebSite.ViewModels.IndexViewModels;
using Attribute = ControleRepresentante.Logic.Models.Attribute;

namespace ControleRepresentante.UnitTests.Controllers
{
    [TestClass]
    public class ClienteControllerTests : CRUDControllerTestScenarioBase<ClienteController, Cliente, IClienteRepository, StatisticsBase>
    {
        private Guid m_VendedorId;
        private Representante m_Representante;
        private const string RazaoSocial = "Razao Social";
        private const string NomeFantasia = "Nome Fantasia";
        private const string CNPJ = "cnpj";
        private const string InscricaoEstadual = "inscricao estadual";
        private const int Codigo = 123;
        private const int Regiao = 456;
        private static DateTime m_ClienteDesde = DateTime.Now;

        protected override ClienteController CreateController(bool isRepresentante = true)
        {
            this.LoginAsAdmin();
            Guid representanteId = this.CreateRepresentante("repre", true, "repreuser");
            m_Representante = RepositoryProvider.GetRepository<IRepresentanteRepository>().GetModelById(representanteId);
            this.CreateRepresentante("otherrepre", false, "other");
            this.Logout();
            this.LoginAs("repreuser");
            m_VendedorId = this.CreateVendedor(new Vendedor
            {
                Nome = "vendedor"
            });
            if (!isRepresentante)
            {
                this.Logout();
            }
            return new ClienteController(RepositoryProvider, SessionConfiguration, ControllerExtensionProvider);
        }

        protected override Cliente CreateModel()
        {
            Cliente cliente = new Cliente
            {
                RazaoSocial = Guid.NewGuid().ToString(),
                NomeFantasia = Guid.NewGuid().ToString(),
                Vendedor = new Vendedor {Id = m_VendedorId},
                Representante = m_Representante,
            };
            return cliente;
        }

        protected override ActionResult Create(ClienteController controller)
        {
            return controller.Create(RazaoSocial, NomeFantasia, m_VendedorId, CNPJ, InscricaoEstadual, m_ClienteDesde, CreateFormCollection());
        }

        private static FormCollection CreateFormCollection()
        {
            return new FormCollection(new NameValueCollection
                                          {
                                              {"codigo", Codigo.ToString()},
                                              {"regiao", Regiao.ToString()}
                                          });
        }

        protected override void VerifyModel(Cliente model)
        {
            Assert.AreEqual(RazaoSocial, model.RazaoSocial);
            Assert.AreEqual(NomeFantasia, model.NomeFantasia);
            Assert.AreEqual(m_ClienteDesde, model.ClienteDesde);
            Assert.AreEqual(m_VendedorId, model.Vendedor.Id);
            Assert.AreEqual(CNPJ, model.CNPJ);
            Assert.AreEqual(InscricaoEstadual, model.InscricaoEstadual);
            Assert.IsNotNull(model.ClienteJolitex);
            Assert.AreEqual(Codigo, model.ClienteJolitex.Codigo);
            Assert.AreEqual(Regiao, model.ClienteJolitex.Regiao);
        }

        protected override ActionResult CreateEmptyFields(ClienteController controller)
        {
            return controller.Create(String.Empty, String.Empty, m_VendedorId, CNPJ, InscricaoEstadual, null, CreateFormCollection());
        }

        protected override void VerifyModelEmptyFields(Cliente model)
        {
            Assert.AreEqual(String.Empty, model.RazaoSocial);
            Assert.AreEqual(String.Empty, model.NomeFantasia);
            Assert.IsNull(model.ClienteDesde);
            Assert.AreEqual(m_VendedorId, model.Vendedor.Id);
            Assert.AreEqual(CNPJ, model.CNPJ);
            Assert.AreEqual(InscricaoEstadual, model.InscricaoEstadual);
            Assert.IsNotNull(model.ClienteJolitex);
            Assert.AreEqual(Codigo, model.ClienteJolitex.Codigo);
            Assert.AreEqual(Regiao, model.ClienteJolitex.Regiao);
        }

        protected override ActionResult CreateDuplicatedModel(ClienteController controller, Cliente model)
        {
            return controller.Create(model.RazaoSocial, model.NomeFantasia, m_VendedorId, CNPJ, InscricaoEstadual, m_ClienteDesde, CreateFormCollection());
        }

        protected override void VerifyDuplicatedModel(Cliente originalModel, Cliente duplicatedModel)
        {
            Assert.AreEqual(originalModel.RazaoSocial, duplicatedModel.RazaoSocial);
            Assert.AreEqual(originalModel.NomeFantasia, duplicatedModel.NomeFantasia);
            Assert.AreEqual(m_VendedorId, duplicatedModel.Vendedor.Id);
            Assert.AreEqual(CNPJ, duplicatedModel.CNPJ);
            Assert.AreEqual(m_ClienteDesde, duplicatedModel.ClienteDesde);
            Assert.AreEqual(InscricaoEstadual, duplicatedModel.InscricaoEstadual);
            Assert.IsNotNull(duplicatedModel.ClienteJolitex);
            Assert.AreEqual(Codigo, duplicatedModel.ClienteJolitex.Codigo);
            Assert.AreEqual(Regiao, duplicatedModel.ClienteJolitex.Regiao);
        }

        protected override ActionResult Edit(ClienteController controller)
        {
            return controller.Edit(RazaoSocial, NomeFantasia, m_VendedorId, CNPJ, InscricaoEstadual, m_ClienteDesde, CreateFormCollection());
        }

        protected override ActionResult EditEmptyFields(ClienteController controller)
        {
            return controller.Edit(String.Empty, String.Empty, m_VendedorId, CNPJ, InscricaoEstadual, null, CreateFormCollection());
        }

        protected override ActionResult EditDuplicatedModel(ClienteController controller, Cliente modelToDuplicate)
        {
            return controller.Edit(modelToDuplicate.RazaoSocial, modelToDuplicate.NomeFantasia, m_VendedorId, CNPJ, InscricaoEstadual, m_ClienteDesde, CreateFormCollection());
        }

        [TestMethod]
        [ExpectedException(typeof(LoginException))]
        public void TestClientesNotAtivoRepresentante()
        {
            ClienteController clienteController = CreateController(false);
            this.LoginAs("other");
            clienteController.Index();
        }

        [TestMethod]
        public void TestCreateAndDeleteFullCliente()
        {
            this.LoginAsAdmin();
            this.CreateRepresentante("my representante", true, "user");
            this.Logout();

            this.LoginAs("user");
            this.CreateAttribute(AttributeType.Cliente, "my attribute");
            Guid vendedorId = this.CreateVendedor(new Vendedor{Nome = "vendedor"});
            Cliente cliente = new Cliente
            {
                RazaoSocial = "razao social",
                NomeFantasia = "nome fantasia",
                CNPJ = "cnpj",
                InscricaoEstadual = "inscricao estadual",
                Vendedor = new Vendedor {Id = vendedorId},
            };
            cliente.AddEndereco(new Endereco
            {
                Bairro = "bairro",
                CEP = "cep",
                Cidade = "cidade",
                Complemento = "complemento",
                Estado = "estado",
                Numero = "numero",
                Observacao = "observacao",
                Rua = "rua",
                Tipo = EnderecoType.Residencial,
                Principal = true
            });
            cliente.AddContato(new Contato
            {
                Tipo = ContatoType.FaxResidencial,
                Valor = "my contato valor",
                Observacao = "my contato observacao",
                Principal = true
            });
            cliente.AddAttributeValue(new AttributeValue
            {
                Attribute = new Attribute { Name = "my attribute" },
                Value = "my attribute value"
            });
            cliente.AddConta(new Conta
            {
                Agencia = "agencia",
                Banco = "banco",
                Numero = "numero",
                Observacao = "observacao",
                Principal = true
            });
            Guid clienteId = this.CreateCliente(cliente);
            this.DeleteCliente(clienteId);
        }

        [TestMethod]
        public void TestUnableToDeleteClienteWithPedido()
        {
            this.LoginAsAdmin();
            this.CreateRepresentante("repre", true, "u");
            this.Logout();
            this.LoginAs("u");
            Guid vendedorId = this.CreateVendedor("vendedor");
            Guid clienteId = this.CreateCliente("nome", vendedorId);
            Guid transportadoraId = this.CreateTransportadora("transportadora");
            Guid fabricaId = this.CreateFabrica("fabrica");
            this.CreatePedido(vendedorId, clienteId, transportadoraId, fabricaId);
            using (ClienteController clienteController = new ClienteController(RepositoryProvider, SessionConfiguration, ControllerExtensionProvider))
            {
                ActionResult actionResult = clienteController.Delete(clienteId);
                Assert.IsInstanceOfType(actionResult, typeof(ViewResult));
                ViewResult viewResult = (ViewResult)actionResult;
                Assert.IsInstanceOfType(viewResult.Model, typeof(DetailsViewModel));
                DetailsViewModel detailsViewModel = (DetailsViewModel)viewResult.Model;
                Assert.IsNotNull(detailsViewModel.Message);
            }
        }

        [TestMethod]
        public void TestBuscaCidade()
        {
            this.LoginAsAdmin();
            this.CreateRepresentante("repre", true, "u");
            this.Logout();
            this.LoginAs("u");
            Guid vendedorId = this.CreateVendedor("vendedor");
            
            Cliente clienteA = new Cliente
            {
                RazaoSocial = "a",
                NomeFantasia = "a",
                Vendedor = new Vendedor {Id = vendedorId}
            };
            clienteA.AddEndereco(new Endereco{Cidade = "a", Estado = "a", Numero = "a", Rua = "a", Principal = true, Tipo = EnderecoType.Comercial});
            this.CreateCliente(clienteA);

            Cliente clienteB = new Cliente
            {
                RazaoSocial = "b",
                NomeFantasia = "b",
                Vendedor = new Vendedor {Id = vendedorId}
            };
            clienteB.AddEndereco(new Endereco { Cidade = "b", Estado = "b", Numero = "b", Rua = "b", Principal = true, Tipo = EnderecoType.Comercial });
            this.CreateCliente(clienteB);

            ClienteController clienteController = new ClienteController(RepositoryProvider, SessionConfiguration, ControllerExtensionProvider);
            clienteController.ControllerContext = new ControllerContext(new MockHttpContext(), new RouteData(), clienteController);
            ActionResult actionResult = clienteController.Search(null, "b", null, null, null, null, null, null, new FormCollection());
            Assert.IsInstanceOfType(actionResult, typeof(ViewResult));
            ViewResult viewResult = (ViewResult) actionResult;
            Assert.IsInstanceOfType(viewResult.Model, typeof(ClienteIndexViewModel));
            ClienteIndexViewModel clienteIndexViewModel = (ClienteIndexViewModel) viewResult.Model;
            Assert.AreEqual(1, clienteIndexViewModel.Models.Count());
            Assert.AreEqual("b", ((Cliente)clienteIndexViewModel.Models.Single()).EnderecoCidade);
        }

        [TestMethod]
        public void TestChangeVendedor()
        {
            this.LoginAsAdmin();
            this.CreateRepresentante("repre", true, "u");
            this.Logout();
            this.LoginAs("u");
            Guid vendedor1Id = this.CreateVendedor("vendedor1");
            Guid vendedor2Id = this.CreateVendedor("vendedor2");
            Guid clienteId = this.CreateCliente("cliente", vendedor1Id);
            ClienteController clienteController = new ClienteController(RepositoryProvider, SessionConfiguration, ControllerExtensionProvider);
            clienteController.Edit(clienteId);
            clienteController.Edit("razaosocial", String.Empty, vendedor2Id, null, null, null);
            IClienteRepository clienteRepository = RepositoryProvider.GetRepository<IClienteRepository>();
            Cliente cliente = clienteRepository.GetModelById(clienteId);
            Assert.AreEqual(vendedor2Id, cliente.Vendedor.Id);
        }
    }
}
